package com.tarena.lbs.attach.service.impl;

import com.tarena.lbs.attach.dao.mapper.AttachMapper;
import com.tarena.lbs.attach.enums.AttachResultEnum;
import com.tarena.lbs.attach.pojo.dto.AttachDTO;
import com.tarena.lbs.attach.pojo.entity.Attach;
import com.tarena.lbs.attach.pojo.param.PicUpdateParam;
import com.tarena.lbs.attach.pojo.po.AttachPO;
import com.tarena.lbs.attach.service.AttachService;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;


@Service
@DubboService
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class AttachServiceImpl implements AttachService {
    @Value("${image_path}")
    private String imagePath;
    @Autowired
    private AttachMapper attachMapper;
    @Override
    public AttachDTO insertAttachInfo(MultipartFile file, String fileUuid) throws BusinessException, IOException {
        // 1. 验证文件
        validateFile(file);

        // 2. 获取文件信息
        String originalFileName = file.getName();
        String fileExtension = FileUtil.getFileExtension(originalFileName);
        String newFileName = fileUuid + (fileExtension.isEmpty() ? "" : "." + fileExtension);

        // 3. 构建完整文件保存路径
        String filePath = Paths.get(imagePath, newFileName).toString();

        // 4. 保存文件到指定目录
        saveFileToDisk(file, filePath);

        // 5. 构建附件实体并保存到数据库
        Attach attach = buildAttachEntity(file, fileUuid, filePath);

        // 在调用处添加更详细的异常处理
        try {
            // 插入操作
            int count = attachMapper.insertAttachInfo(attach);
            if (count <= 0) {
                // 如果插入失败，删除已保存的文件
                try {
                    Files.deleteIfExists(Paths.get(filePath));
                } catch (IOException e) {
                    log.error("Failed to delete orphaned file: {}", filePath, e);
                }
                log.error("Failed to insert attach record: {}", attach);
                throw new BusinessException(AttachResultEnum.SYSTEM_ERROR);
            }
        } catch (DuplicateKeyException e) {
            // 同样需要清理文件
            try {
                Files.deleteIfExists(Paths.get(filePath));
            } catch (IOException ioException) {
                log.error("Failed to delete orphaned file after duplicate key: {}", filePath, ioException);
            }
            log.error("Duplicate file UUID: {}", fileUuid, e);
            throw new BusinessException(AttachResultEnum.FILE_FAIL);
        }

        // 6. 返回DTO对象
        return convertToDTO(attach);
    }

    private Attach buildAttachEntity(MultipartFile file, String fileUuid, String filePath) {
        Attach attach = new Attach();
        attach.setFileUuid(fileUuid);
//        attach.setFileName(fileName);
        attach.setFileSize(file.getSize());
        attach.setContentType(file.getContentType());
        attach.setFilePath(filePath);
        return attach;
    }

    private AttachDTO convertToDTO(Attach attach) {
        AttachDTO attachDTO = new AttachDTO();
        BeanUtils.copyProperties(attach, attachDTO);
        return attachDTO;
    }

    private void validateFile(MultipartFile file) throws BusinessException {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(AttachResultEnum.CONTENT_NOT_EXISTS);
        }

        // 验证文件大小
        if (file.getSize() > 10 * 1024 * 1024) { // 10MB限制
            throw new BusinessException(AttachResultEnum.FILE_SIZE_EXCEED);
        }

        // 验证文件类型
        String fileExtension = FileUtil.getFileExtension(file.getOriginalFilename());
        if (!isAllowedFileType(fileExtension)) {
            throw new BusinessException(AttachResultEnum.FILE_TYPE_NOT_SUPPORTED);
        }
    }

    /**
     * 检查文件类型是否允许
     */
    private boolean isAllowedFileType(String fileExtension) {
        String[] allowedTypes = {"jpg", "jpeg", "png", "gif", "pdf", "doc", "docx", "xls", "xlsx"};
        return Arrays.asList(allowedTypes).contains(fileExtension.toLowerCase());
    }

    /**
     * 保存文件到磁盘
     */
    private void saveFileToDisk(MultipartFile file, String filePath) throws IOException {
        File dest = new File(filePath);
        // 确保父目录存在
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        // 保存文件
        file.transferTo(dest);
    }
    public class FileUtil {
        /**
         * 获取文件扩展名
         */
        public static String getFileExtension(String fileName) {
            if (fileName == null || fileName.lastIndexOf(".") == -1) {
                return "";
            }
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        }

        /**
         * 生成临时文件并返回最终文件名
         */
        public static String makeTempFile(MultipartFile file, String basePath, String fileUuid) throws IOException, IOException {
            String originalFileName = file.getName();
            String fileExtension = getFileExtension(originalFileName);
            String newFileName = fileUuid + (fileExtension.isEmpty() ? "" : "." + fileExtension);

            Path path = Paths.get(basePath, newFileName);
            Files.createDirectories(path.getParent());

            try (InputStream inputStream = file.getInputStream()) {
                Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING);
            }

            return newFileName;
        }
    }

}
